package com.intelligent.ispc.core.service.impl;

import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.intelligent.ispc.common.mapper.BeanMapper;
import com.intelligent.ispc.common.mapper.BeanUtil;
import com.intelligent.ispc.common.mapper.JsonMapper;
import com.intelligent.ispc.common.persistence.DynamicSpecifications;
import com.intelligent.ispc.common.persistence.SearchFilter;
import com.intelligent.ispc.common.utils.ApplicationException;
import com.intelligent.ispc.common.utils.ApplicationUtil;
import com.intelligent.ispc.common.utils.ExceptionMessages;
import com.intelligent.ispc.common.utils.StringUtils;
import com.intelligent.ispc.core.dto.*;
import com.intelligent.ispc.core.entity.*;
import com.intelligent.ispc.core.repository.jpa.*;
import com.intelligent.ispc.core.repository.mongo.GRRTestDataDao;
import com.intelligent.ispc.core.service.*;
import com.intelligent.ispc.external.rcall.service.AnalysisService;
import com.intelligent.ispc.utils.*;
import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import java.io.File;
import java.util.*;

/**
 * Created by Julia.Zhou on 2016/06/02.
 */
@Service
public class GRRTestDataServiceImpl implements GRRTestDataService {
    private static Logger logger = LoggerFactory.getLogger(GRRTestDataServiceImpl.class);

    @Autowired
    private ProjectService projectService;

    @Autowired
    private AnalysisService analysisService;

    @Autowired
    private GRRTestDataDao grrTestDataDao;

    @Autowired
    private GRRItemDao grrItemDao;

    @Autowired
    private GRRAnovaDao grrAnovaDao;

    @Autowired
    private GRRSourceDao grrSourceDao;

    @Autowired
    private GRRSummaryDao grrSummaryDao;

    @Autowired
    private PsGRRDao psGRRDao;

    protected JsonMapper mapper = JsonMapper.nonDefaultMapper();


    @Override
    public List<GRRAnalysisParamDto> searchGRRTestItems(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null || searchParams.get(Constant.GRR_NAME) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        List<GRRDataDto> grrDataDtoList = this.searchGRRTestData(searchParams);
        GRRTestData grrTestData = grrTestDataDao.findGRRTestData(searchParams);
        List<GRRAnalysisParamDto> grrAnalysisParamDtoList = Lists.newLinkedList();
        if (grrDataDtoList == null || grrDataDtoList.isEmpty() || grrTestData == null
                || grrTestData.getTestItems() == null || grrTestData.getTestItems().isEmpty()) {
            return grrAnalysisParamDtoList;
        }
        Map<String, List<String>> itemNameList = new LinkedHashMap<>();
        for (GRRDataDto grrDataDto : grrDataDtoList) {
            if (!grrDataDto.getCheck()) {
                continue;
            }
            for (BaseDto baseDto : grrDataDto.getColValueDtoList()) {
                String itemName = baseDto.getKey();
                String itemValue = (String) baseDto.getValue();
                if (StringUtils.isBlankWithSpecialNumber(itemValue)) {
                    itemValue = Constant.GLOBAL_NAN;
                }
                if (!itemNameList.containsKey(itemName)) {
                    List<String> itemValueList = Lists.newLinkedList();
                    itemValueList.add(itemValue);
                    itemNameList.put(itemName, itemValueList);
                } else {
                    itemNameList.get(itemName).add(itemValue);
                }
            }
        }
        for (String key : itemNameList.keySet()) {
            List<String> itemValueList = itemNameList.get(key);
            boolean invalidate = false;
            double[] itemValues = new double[itemValueList.size()];
            for (int i = 0; i < itemValueList.size(); i++) {
                String itemValue = itemValueList.get(i);
                if (!StringUtils.isBlankWithSpecialNumber(itemValue) && !StringUtils.isNumeric(itemValue)) {
                    itemValue = Constant.GLOBAL_NAN;
                    invalidate = true;
                }
                if (StringUtils.isBlankWithSpecialNumber(itemValue)) {
                    itemValue = Constant.GLOBAL_NAN;
                }
                itemValues[i] = Double.valueOf(itemValue);
            }

            GRRAnalysisParamDto grrAnalysisParamDto = new GRRAnalysisParamDto();
            for (TestItem testItem : grrTestData.getTestItems()) {
                if (key.equals(testItem.getName())) {
                    grrAnalysisParamDto.setItemName(key);
                    grrAnalysisParamDto.setInvalidate(invalidate);
                    grrAnalysisParamDto.setUsl(Double.valueOf(StringUtils.isNumeric(testItem.getUpperLimit()) ? testItem.getUpperLimit() : Constant.GLOBAL_NAN));
                    grrAnalysisParamDto.setLsl(Double.valueOf(StringUtils.isNumeric(testItem.getLowerLimit()) ? testItem.getLowerLimit() : Constant.GLOBAL_NAN));
                    grrAnalysisParamDto.setAnalysisData(itemValues);
                    grrAnalysisParamDtoList.add(grrAnalysisParamDto);
                    break;
                }
            }
        }
        return grrAnalysisParamDtoList;
    }

    @Override
    public GRRAnalysisParamDto searchGRRTestItem(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null || searchParams.get(Constant.GRR_NAME) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        GRRTestData grrTestData = grrTestDataDao.findGRRTestData(searchParams);
        List<GRRDataDto> grrDataDtoList = this.searchGRRTestData(searchParams);

        GRRAnalysisParamDto grrAnalysisParamDto = new GRRAnalysisParamDto();
        if (grrDataDtoList == null || grrDataDtoList.isEmpty() || grrTestData == null
                || grrTestData.getTestItems() == null || grrTestData.getTestItems().isEmpty()) {
            return grrAnalysisParamDto;
        }
        String itemNameTemp = (String) searchParams.get(Constant.GLOBAL_ITEM_NAME);
        Map<String, List<String>> itemNameList = new LinkedHashMap<>();
        for (GRRDataDto grrDataDto : grrDataDtoList) {
            if (!grrDataDto.getCheck()) {
                continue;
            }
            for (BaseDto baseDto : grrDataDto.getColValueDtoList()) {
                String itemName = baseDto.getKey();
                if (itemNameTemp != null && itemNameTemp.equals(itemName)) {
                    String itemValue = (String) baseDto.getValue();
                    if (!StringUtils.isBlankWithSpecialNumber(itemValue) && !StringUtils.isNumeric(itemValue)) {
                        itemValue = Constant.GLOBAL_NAN;
                    }
                    if (StringUtils.isBlankWithSpecialNumber(itemValue)) {
                        itemValue = Constant.GLOBAL_NAN;
                    }
                    if (!itemNameList.containsKey(itemName)) {
                        List<String> itemValueList = Lists.newLinkedList();
                        itemValueList.add(itemValue);
                        itemNameList.put(itemName, itemValueList);
                    } else {
                        itemNameList.get(itemName).add(itemValue);
                    }
                }
            }
        }
        //refresh usl and lsl
        Double usl = Double.valueOf(Constant.GLOBAL_NAN);
        Double lsl = Double.valueOf(Constant.GLOBAL_NAN);

        if (searchParams.get(Constant.GRR_USL) != null && StringUtils.isNumeric((String) searchParams.get(Constant.GRR_USL))) {
            usl = Double.valueOf((String) searchParams.get(Constant.GRR_USL));
        }

        if (searchParams.get(Constant.GRR_LSL) != null && StringUtils.isNumeric((String) searchParams.get(Constant.GRR_LSL))) {
            lsl = Double.valueOf((String) searchParams.get(Constant.GRR_LSL));
        }
        //only one
        for (String key : itemNameList.keySet()) {
            List<String> itemValueList = itemNameList.get(key);
            double[] itemValues = new double[itemValueList.size()];
            for (int i = 0; i < itemValueList.size(); i++) {
                itemValues[i] = Double.valueOf(itemValueList.get(i));
            }

            for (TestItem testItem : grrTestData.getTestItems()) {
                if (key.equals(testItem.getName())) {
                    grrAnalysisParamDto.setItemName(key);
                    if (usl.isNaN() && lsl.isNaN()) {
                        grrAnalysisParamDto.setUsl(Double.valueOf(StringUtils.isNumeric(testItem.getUpperLimit()) ? testItem.getUpperLimit() : Constant.GLOBAL_NAN));
                        grrAnalysisParamDto.setLsl(Double.valueOf(StringUtils.isNumeric(testItem.getLowerLimit()) ? testItem.getLowerLimit() : Constant.GLOBAL_NAN));
                    } else {
                        grrAnalysisParamDto.setUsl(usl.doubleValue());
                        grrAnalysisParamDto.setLsl(lsl.doubleValue());
                    }
                    grrAnalysisParamDto.setAnalysisData(itemValues);
                    break;
                }
            }
        }
        return grrAnalysisParamDto;
    }

    @Override
    public List<String> searchDistinctGRRName(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

        List<BaseDto> dtoList = Lists.newLinkedList();
        List<String> results = grrTestDataDao.findDistinctGRRTestDatas(searchParams, "grrName");
        logger.debug("Searching grrName, total elements:{}", results.size());
        return results;
    }

    @Override
    public List<String> searchDistinctStation(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null || searchParams.get(Constant.GRR_NAME) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        searchParams.put("isNeedItems", false);
        searchParams.put("isNeedDutAttributes", false);
        List<String> results = grrTestDataDao.findDistinctGRRTestDatas(searchParams, "testData.stationId");
        logger.debug("Searching station, total elements:{}", results.size());
        return results;
    }

    @Override
    @Deprecated
    public List<StationDto> searchStationByGRRName(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null || searchParams.get(Constant.GRR_NAME) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        String projectId = (String) searchParams.get(Constant.GLOBAL_PROJECT_ID);
        List<GRRTestData> grrTestDatas = grrTestDataDao.findGRRTestDatas(searchParams);
        PSGRRDto psGRRDto = projectService.findPSGRRByProject(projectId);
        String[] testStrategy = null;
        if (Model.SLOT.getCode().equals(psGRRDto.getModel())) {
            GRRItemDto grrItemDto = this.searchGRRItem(searchParams);
            AnalysisKeysDto analysisKeysDto = mapper.fromJson(grrItemDto.getAnalysisKeys(), AnalysisKeysDto.class);
            if (analysisKeysDto != null && StringUtils.isNotBlank(analysisKeysDto.getDimensionValue())) {
                testStrategy = analysisKeysDto.getDimensionValue().split(";");
            }
        }
        List<StationDto> stationDtoList = Lists.newLinkedList();
        Map<String, List<String>> stationMap = new LinkedHashMap<>();
        for (GRRTestData grrTestData : grrTestDatas) {
            if (grrTestData.getTestData() == null) {
                continue;
            }
            String station = (String) grrTestData.getTestData().get(TestData.PSA_STATION_ID);
            if (testStrategy== null || testStrategy.length == 0) {
                String slot = (String) grrTestData.getTestData().get(TestData.PSA_SLOT_NO);
                if (!stationMap.containsKey(station)) {
                    List<String> slotList = Lists.newLinkedList();
                    slotList.add(slot);
                    stationMap.put(station, slotList);
                } else {
                    if (!stationMap.get(station).contains(slot)) {
                        stationMap.get(station).add(slot);
                    }
                }
            } else {
                if (!stationMap.containsKey(station)) {
                    List<String> slotList = Lists.newLinkedList();
                    for (int z = 0; z < testStrategy.length; z++) {
                        slotList.add(testStrategy[z]);
                    }
                    stationMap.put(station, slotList);
                }
            }
        }

        for (String key : stationMap.keySet()) {
            StationDto stationDto = new StationDto();
            stationDto.setStationId(key);
            stationDto.setSlotNos(stationMap.get(key));
            stationDto.setProjectId(projectId);
            stationDtoList.add(stationDto);
        }
        return stationDtoList;
    }

    @Override
    public List<AnalysisKeyResultDto> searchAnalysisKeys(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null || searchParams.get(Constant.GRR_NAME) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

            String projectId = (String) searchParams.get(Constant.GLOBAL_PROJECT_ID);
            List<GRRTestData> grrTestDatas = grrTestDataDao.findGRRTestDatas(searchParams);
            PSGRRDto psGRRDto = projectService.findPSGRRByProject(projectId);

            String[] testStrategy = null;
            GRRItemDto grrItemDto = this.searchGRRItem(searchParams);
            AnalysisKeysDto analysisKeysDto = mapper.fromJson(grrItemDto.getAnalysisKeys(), AnalysisKeysDto.class);
            if (Model.SLOT.getCode().equals(psGRRDto.getModel())) {
                if (analysisKeysDto != null && StringUtils.isNotBlank(analysisKeysDto.getDimensionValue())) {
                    testStrategy = analysisKeysDto.getDimensionValue().split(";");
                }
            }
            String group1Key = analysisKeysDto.getGroup1Key();
            String group2Key = analysisKeysDto.getGroup2Key();
            String dimensionKey = analysisKeysDto.getDimensionKey();

            String db_group1Key = analysisKeysDto.getGroup1Key();
            String db_group2Key = analysisKeysDto.getGroup2Key();
            String db_dimensionKey = analysisKeysDto.getDimensionKey();

            List<AnalysisKeyResultDto> analysisKeyResultDtoList = Lists.newLinkedList();
            Map<String, List<String>> groupMap = new LinkedHashMap<>();
            for (GRRTestData grrTestData : grrTestDatas) {
                if (grrTestData.getTestData() == null) {
                    continue;
                }
                String group1KeyValue = null;
                String group2KeyValue = null;
                String dimensionKeyValue = null;
                if ((Boolean) analysisKeysDto.isGroup1KeyFlag()) {
                    group1KeyValue = (String) grrTestData.getTestData().get(group1Key) == null ? "" : (String) grrTestData.getTestData().get(group1Key);
                    db_group1Key = Constant.GLOBAL_TEST_DATA + group1Key;
                }

                if (StringUtils.isNotBlank(group2Key) && (Boolean) analysisKeysDto.isGroup2KeyFlag()) {
                    group2KeyValue = (String) grrTestData.getTestData().get(group2Key) == null ? "" : (String) grrTestData.getTestData().get(group2Key);
                    db_group2Key = Constant.GLOBAL_TEST_DATA + group2Key;
                }

                if (StringUtils.isNotBlank(dimensionKey) && (Boolean) analysisKeysDto.isDimensionKeyFlag()) {
                    dimensionKeyValue = (String) grrTestData.getTestData().get(dimensionKey) == null ? "" : (String) grrTestData.getTestData().get(dimensionKey);
                    db_dimensionKey = Constant.GLOBAL_TEST_DATA + dimensionKey;
                }

                if (grrTestData.getDutAttributes() != null && !grrTestData.getDutAttributes().isEmpty()) {
                    for (DUTAttribute dUTAttribute : grrTestData.getDutAttributes()) {
                        if (!(Boolean) analysisKeysDto.isGroup1KeyFlag() && dUTAttribute.getAttributeName().equals(group1Key)) {
                            group1KeyValue = dUTAttribute.getAttributeValue() == null ? "" : dUTAttribute.getAttributeValue();
                            db_group1Key = group1Key;
                        } else if (StringUtils.isNotBlank(group2Key) && !(Boolean) analysisKeysDto.isGroup2KeyFlag() && dUTAttribute.getAttributeName().equals(group2Key)) {
                            group2KeyValue = dUTAttribute.getAttributeValue() == null ? "" : dUTAttribute.getAttributeValue();
                            db_group2Key = group2Key;
                        } else if (StringUtils.isNotBlank(dimensionKey) && !(Boolean) analysisKeysDto.isDimensionKeyFlag() && dUTAttribute.getAttributeName().equals(dimensionKey)) {
                            dimensionKeyValue = dUTAttribute.getAttributeValue() == null ? "" : dUTAttribute.getAttributeValue();
                            db_dimensionKey = dimensionKey;
                        }
                    }
                }

                if (testStrategy== null || testStrategy.length == 0) {
                    if (StringUtils.isNotBlank(group2Key)) {
                        if (!groupMap.containsKey(group1KeyValue)) {
                            List<String> group2List = Lists.newLinkedList();
                            group2List.add(group2KeyValue);
                            groupMap.put(group1KeyValue, group2List);
                        } else {
                            if (!groupMap.get(group1KeyValue).contains(group2KeyValue)) {
                                groupMap.get(group1KeyValue).add(group2KeyValue);
                            }
                        }
                    } else {
                        if (!groupMap.containsKey(group1KeyValue)) {
                            List<String> group2List = Lists.newLinkedList();
                            groupMap.put(group1KeyValue, group2List);
                        }
                    }

                } else {
                    String analysisKeys = null;
                    if (StringUtils.isNotBlank(group2Key)) {
                        analysisKeys = group1KeyValue + Constant.GLOBAL_SEPARATOR + group2KeyValue;
                    } else {
                        analysisKeys = group1KeyValue;
                    }

                    if (analysisKeys != null && !groupMap.containsKey(analysisKeys)) {
                        List<String> dimensionList = Lists.newLinkedList();
                        for (int z = 0; z < testStrategy.length; z++) {
                            dimensionList.add(testStrategy[z]);
                        }
                        groupMap.put(analysisKeys, dimensionList);
                    }
                }
            }

            for (String mapKey : groupMap.keySet()) {
                AnalysisKeyResultDto analysisKeyResultDto = new AnalysisKeyResultDto();
                analysisKeyResultDto.setGroup1Key(db_group1Key);
                if (Model.SLOT.getCode().equals(psGRRDto.getModel())) {
                    analysisKeyResultDto.setGroup2Key(db_group2Key);
                    analysisKeyResultDto.setDimensionKey(db_dimensionKey);
                    analysisKeyResultDto.setGroup2KeyFlag(analysisKeysDto.isGroup2KeyFlag());
                    analysisKeyResultDto.setDimensionKeyFlag(analysisKeysDto.isDimensionKeyFlag());
                } else {
                    analysisKeyResultDto.setDimensionKey(db_group2Key);
                    analysisKeyResultDto.setDimensionKeyFlag(analysisKeysDto.isGroup2KeyFlag());
                }
                analysisKeyResultDto.setGroupKey(mapKey);
                analysisKeyResultDto.setDimensionList(groupMap.get(mapKey));

                analysisKeyResultDto.setGroup1KeyFlag(analysisKeysDto.isGroup1KeyFlag());
                analysisKeyResultDtoList.add(analysisKeyResultDto);
            }
            return analysisKeyResultDtoList;
    }

    @Override
    public List<BaseDto> searchDistinctTestItemName(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null || searchParams.get(Constant.GRR_NAME) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

        GRRItemDto grrItemDto = this.searchGRRItem(searchParams);
        List<BaseDto> itemNameAllLists = Lists.newLinkedList();
        if (StringUtils.isNotBlank(grrItemDto.getTestItemNames())) {
            itemNameAllLists = mapper.fromJson(grrItemDto.getTestItemNames(), mapper.contructCollectionType(List.class, BaseDto.class));
        }
        return itemNameAllLists;
    }

    @Override
    public List<GRRTestDataDto> searchGRRTestDatas(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null || searchParams.get(Constant.GRR_NAME) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        List<GRRTestData> grrTestDataList = grrTestDataDao.findGRRTestDatas(searchParams);
        List<GRRTestDataDto> grrTestDataDtoList = Lists.newLinkedList();

        GRRItemDto grrItemDto = this.searchGRRItem(searchParams);
        List<BaseDto> itemNameAllLists = mapper.fromJson(grrItemDto.getTestItemNames(), mapper.contructCollectionType(List.class, BaseDto.class));
        List<String> itemNameCheckedLists = Lists.newLinkedList();
        if (itemNameAllLists != null && !itemNameAllLists.isEmpty()) {
            for (BaseDto baseDto : itemNameAllLists) {
                if ((boolean) baseDto.getValue()) {
                    itemNameCheckedLists.add(baseDto.getKey());
                }
            }
        }

        for (GRRTestData grrTestData : grrTestDataList) {
            if (grrTestData.getTestData() == null || grrTestData.getTestItems() == null || grrTestData.getTestItems().isEmpty()) {
                continue;
            }
            GRRTestDataDto grrTestDataDto = new GRRTestDataDto();
            BeanMapper.copy(grrTestData, grrTestDataDto);
            List<TestItem> testItems  = grrTestData.getTestItems();
            grrTestDataDto.getTestItems().clear();
            for (TestItem testItem : testItems) {
                if (itemNameCheckedLists.contains(testItem.getName())) {
                    grrTestDataDto.getTestItems().add(testItem);
                }
            }
            grrTestDataDtoList.add(grrTestDataDto);
        }
        return grrTestDataDtoList;
    }

    @Override
    public List<GRRDataDto> searchGRRTestData(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null || searchParams.get(Constant.GRR_NAME) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        String projectId = (String) searchParams.get(Constant.GLOBAL_PROJECT_ID);

        PSGRRDto psGRRDto = projectService.findPSGRRByProject(projectId);
        searchParams.put(Constant.GRR_MODEL_VALUE, psGRRDto.getModel());

        List<GRRTestData> grrTestDataList = grrTestDataDao.findGRRTestDatas(searchParams);
        List<GRRDataDto> grrDataDtoList = Lists.newLinkedList();

        Map<String, List<GRRTestData>> partMap = new LinkedHashMap<>();


        GRRItemDto grrItemDto = this.searchGRRItem(searchParams);

        if (StringUtils.isBlank(grrItemDto.getTestItemNames())) {
            return grrDataDtoList;
        }

        Integer operatorValue = Integer.valueOf(grrItemDto.getOperatorValue());
        Integer trialValue = Integer.valueOf(grrItemDto.getTrialValue());
        Integer partValue = Integer.valueOf(grrItemDto.getPartValue());
        Integer total = operatorValue * trialValue * partValue;
        AnalysisKeysDto analysisKeysDto = mapper.fromJson(grrItemDto.getAnalysisKeys(), AnalysisKeysDto.class);

        searchParams.put(Constant.GRR_OPERATOR_VALUE, Double.valueOf(operatorValue));
        searchParams.put(Constant.GRR_PART_VALUE, Double.valueOf(partValue));
        searchParams.put(Constant.GRR_TRIAL_VALUE, Double.valueOf(trialValue));
        //refresh sigma
        if (searchParams.get(Constant.GRR_SIGMA_PARAM) != null) {
            searchParams.put(Constant.GRR_SIGMA_VALUE, Double.valueOf(StringUtils.isNumeric((String) searchParams.get(Constant.GRR_SIGMA_PARAM)) ? (String) searchParams.get(Constant.GRR_SIGMA_PARAM) : Constant.GLOBAL_NAN));
        } else {
            searchParams.put(Constant.GRR_SIGMA_VALUE, Double.valueOf(StringUtils.isNumeric(psGRRDto.getSigma()) ? psGRRDto.getSigma() : Constant.GLOBAL_NAN));
        }
        searchParams.put(Constant.GRR_RULE_VALUE, psGRRDto.getRule());

        List<GRRDataDto> grrDataDtoNormalList = Lists.newLinkedList();
        List<GRRDataDto> grrDataDtoMoreList = Lists.newLinkedList();
        Map<String, List<GRRDataDto>> groupMap = new LinkedHashMap<>();

        BaseDto baseDtoResult = null;
        List<BaseDto> itemNameAllLists = mapper.fromJson(grrItemDto.getTestItemNames(), mapper.contructCollectionType(List.class, BaseDto.class));

        List<String> itemNameCheckedLists = Lists.newLinkedList();
        //filter itemName
        if (searchParams.containsKey(Constant.GRR_EXPORT_ITEM_NAMES)) {
            itemNameCheckedLists = mapper.fromJson((String) searchParams.get(Constant.GRR_EXPORT_ITEM_NAMES), List.class);
        } else {
            if (itemNameAllLists != null && !itemNameAllLists.isEmpty()) {
                for (BaseDto baseDto : itemNameAllLists) {
                    if ((boolean) baseDto.getValue()) {
                        itemNameCheckedLists.add(baseDto.getKey());
                    }
                }
            }
        }

        for (GRRTestData grrTestData : grrTestDataList) {
            if (grrTestData.getTestData() == null || grrTestData.getTestItems() == null || grrTestData.getTestItems().isEmpty()) {
                continue;
            }
            String partKeyValue = null;
            if (analysisKeysDto.isPartKeyFlag()) {
                partKeyValue = (String) grrTestData.getTestData().get(analysisKeysDto.getPartKey());
            } else {
                if (grrTestData.getDutAttributes() != null && !grrTestData.getDutAttributes().isEmpty()) {
                    for (DUTAttribute dUTAttribute : grrTestData.getDutAttributes()) {
                        if (!analysisKeysDto.isPartKeyFlag() && dUTAttribute.getAttributeName().equals(analysisKeysDto.getPartKey())) {
                            partKeyValue = dUTAttribute.getAttributeValue();
                            break;
                        }
                    }
                }
            }
            if (!partMap.containsKey(partKeyValue)) {
                List<GRRTestData> grrTestDataTempList = Lists.newLinkedList();
                grrTestDataTempList.add(grrTestData);
                partMap.put(partKeyValue, grrTestDataTempList);
            } else {
                partMap.get(partKeyValue).add(grrTestData);
            }
        }

        String itemNameTemp = null;
        if (searchParams.containsKey(Constant.GLOBAL_ITEM_NAME)) {
            itemNameTemp = (String) searchParams.get(Constant.GLOBAL_ITEM_NAME);
        }

        String grrName = (String) searchParams.get(Constant.GRR_NAME);
        String stationAndSlot = getAnalysisKeys(searchParams);
        String searchKey = projectId + "," + grrName + "," + stationAndSlot;

        List<BaseDto> oldItemValueIncludeIdList = mapper.fromJson(grrItemDto.getIncludeIds(), mapper.contructCollectionType(List.class, BaseDto.class));
        List<BaseDto> oldItemValueExcludeIdList = mapper.fromJson(grrItemDto.getExcludeIds(), mapper.contructCollectionType(List.class, BaseDto.class));
        List<String> oldIncludeIds = Lists.newLinkedList();
        List<String> oldExcludeIds = Lists.newLinkedList();
        //filter testData
        if (oldItemValueIncludeIdList != null && !oldItemValueIncludeIdList.isEmpty()) {
            for (int i = 0; i < oldItemValueIncludeIdList.size(); i++) {
                BaseDto oldIncludeIdDto = oldItemValueIncludeIdList.get(i);
                BaseDto oldExcludeIdDto = oldItemValueExcludeIdList.get(i);
                if (oldIncludeIdDto.getKey().equals(searchKey)) {
                    oldIncludeIds = mapper.fromJson((String) oldIncludeIdDto.getValue(), List.class);
                    oldExcludeIds = mapper.fromJson((String) oldExcludeIdDto.getValue(), List.class);
                }
            }
        }
        boolean isMore = false;
        int partSum = 0;
        if (Model.SLOT.getCode().equals(psGRRDto.getModel())) {
            String testStrategy = this.getAnalysisKeys(searchParams);
            if (StringUtils.isBlank(testStrategy)) {
                throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
            }
            for (String key : partMap.keySet()) {
                List<GRRTestData> valueMap = partMap.get(key);
                String[] dimensions = testStrategy.substring(testStrategy.lastIndexOf("_") + 1, testStrategy.length()).split(",");
                for (int z = 0; z < dimensions.length; z++) {
                    String dimension = dimensions[z];
                    Integer trial = 1, k = 1, group = 1, totalCount = 0;
                    String moreGroupKey = key + dimension;
                    for (GRRTestData grrTestData : valueMap) {
                        totalCount++;
                        String dimensionKeyValue = null;
                        if (analysisKeysDto.isDimensionKeyFlag()) {
                            dimensionKeyValue = (String) grrTestData.getTestData().get(analysisKeysDto.getDimensionKey());
                        } else {
                            if (grrTestData.getDutAttributes() != null && !grrTestData.getDutAttributes().isEmpty()) {
                                for (DUTAttribute dUTAttribute : grrTestData.getDutAttributes()) {
                                    if (!analysisKeysDto.isDimensionKeyFlag() && dUTAttribute.getAttributeName().equals(analysisKeysDto.getDimensionKey())) {
                                        dimensionKeyValue = dUTAttribute.getAttributeValue();
                                        break;
                                    }
                                }
                            }
                        }
                        if (totalCount == valueMap.size() && !dimension.equals(dimensionKeyValue) && grrDataDtoMoreList.size() != 0) {
                            List<GRRDataDto> grrTestDataDtoList1 = Lists.newLinkedList();
                            grrTestDataDtoList1.addAll(grrDataDtoMoreList);
                            if (!groupMap.containsKey(moreGroupKey)) {
                                groupMap.put(moreGroupKey, grrTestDataDtoList1);
                            } else {
                                groupMap.get(moreGroupKey).addAll(grrTestDataDtoList1);
                            }
                            grrDataDtoMoreList.clear();
                        }

                        if (dimension.equals(dimensionKeyValue)) {
                            GRRDataDto grrDataDto = new GRRDataDto();
                            grrDataDto.setPart(key);
                            grrDataDto.setId(grrTestData.getId());
                            grrDataDto.setOperator(dimension);

                            if (oldExcludeIds.contains(grrTestData.getId())) {
                                grrDataDto.setTrial("");
                                isMore = true;
                            } else {
                                grrDataDto.setTrial(trial.toString());
                                if (k - trialValue > 0) {
                                    if (!oldIncludeIds.contains(grrTestData.getId())) {
                                        grrDataDto.setTrial("");
                                        isMore = true;
                                    }
                                }
                            }

                            List<BaseDto> testItemNameList = Lists.newLinkedList();
                            for (TestItem testItem : grrTestData.getTestItems()) {
                                String itemName = testItem.getName();
                                if (itemNameTemp != null) {
                                    if (itemNameTemp.equals(itemName) && itemNameCheckedLists.contains(itemName)) {
                                        baseDtoResult = new BaseDto();
                                        baseDtoResult.setKey(itemName);
                                        baseDtoResult.setValue(testItem.getTestedValue());
                                        testItemNameList.add(baseDtoResult);
                                        break;
                                    }
                                } else {
                                    if (!itemNameCheckedLists.contains(itemName)) {
                                        continue;
                                    }
                                    if (testItemNameList.size() == itemNameCheckedLists.size()) {
                                        break;
                                    }
                                    baseDtoResult = new BaseDto();
                                    baseDtoResult.setKey(itemName);
                                    baseDtoResult.setValue(testItem.getTestedValue());
                                    testItemNameList.add(baseDtoResult);
                                }
                            }
                            k++;
                            grrDataDto.setColValueDtoList(testItemNameList);

                            if (grrDataDtoNormalList.size() >= total){
                                grrDataDto.setTrial("");
                                grrDataDto.setCheck(false);
                                grrDataDtoMoreList.add(grrDataDto);
                                isMore = false;
                                List<GRRDataDto> grrTestDataDtoList1 = Lists.newLinkedList();
                                if (grrDataDtoMoreList.size() - trialValue == 0) {
                                    grrTestDataDtoList1.addAll(grrDataDtoMoreList);
                                    if (!groupMap.containsKey(String.valueOf(group))) {
                                        groupMap.put(String.valueOf(group), grrTestDataDtoList1);
                                    } else {
                                        groupMap.get(String.valueOf(group)).addAll(grrTestDataDtoList1);
                                    }
                                    group++;
                                    grrDataDtoMoreList.clear();
                                } else {
                                    if (totalCount == valueMap.size() && (grrDataDtoMoreList.size() - trialValue != 0)) {
                                        grrTestDataDtoList1.addAll(grrDataDtoMoreList);
                                        if (!groupMap.containsKey(moreGroupKey)) {
                                            groupMap.put(moreGroupKey, grrTestDataDtoList1);
                                        } else {
                                            groupMap.get(moreGroupKey).addAll(grrTestDataDtoList1);
                                        }

                                        grrDataDtoMoreList.clear();
                                    }
                                }
                            } else {
                                if (isMore) {
                                    grrDataDto.setCheck(false);
                                    grrDataDtoMoreList.add(grrDataDto);
                                    isMore = false;
                                    List<GRRDataDto> grrTestDataDtoList1 = Lists.newLinkedList();
                                    if (grrDataDtoMoreList.size() - trialValue == 0) {
                                        grrTestDataDtoList1.addAll(grrDataDtoMoreList);
                                        if (!groupMap.containsKey(String.valueOf(group))) {
                                            groupMap.put(String.valueOf(group), grrTestDataDtoList1);
                                        } else {
                                            groupMap.get(String.valueOf(group)).addAll(grrTestDataDtoList1);
                                        }
                                        group++;
                                        grrDataDtoMoreList.clear();
                                    } else {
                                        if (totalCount == valueMap.size() && (grrDataDtoMoreList.size() - trialValue != 0)) {
                                            grrTestDataDtoList1.addAll(grrDataDtoMoreList);
                                            if (!groupMap.containsKey(moreGroupKey)) {
                                                groupMap.put(moreGroupKey, grrTestDataDtoList1);
                                            } else {
                                                groupMap.get(moreGroupKey).addAll(grrTestDataDtoList1);
                                            }

                                            grrDataDtoMoreList.clear();
                                        }
                                    }
                                } else {
                                    trial++;
                                    grrDataDto.setCheck(true);
                                    grrDataDtoNormalList.add(grrDataDto);
                                }
                            }
                        }
                    }
                    partSum++;
                }
            }
            grrDataDtoList.addAll(grrDataDtoNormalList);
            if (groupMap != null && !groupMap.isEmpty()) {
                for (String group : groupMap.keySet()) {
                    grrDataDtoMoreList.addAll(groupMap.get(group));
                }
            }
            grrDataDtoList.addAll(grrDataDtoMoreList);
        } else {
            if (TestStrategy.OPERATOR.getCode().equals(analysisKeysDto.getDimensionValue())) {
                for (String key : partMap.keySet()) {
                    List<GRRTestData> valueMap = partMap.get(key);
                    Integer operator = 1, trial = 1, k = 1;
                    for (GRRTestData grrTestData : valueMap) {
                        GRRDataDto grrDataDto = new GRRDataDto();
                        grrDataDto.setPart(key);
                        grrDataDto.setId(grrTestData.getId());

                        if (oldExcludeIds.contains(grrTestData.getId())) {
                            grrDataDto.setOperator("");
                            grrDataDto.setTrial("");
                            isMore = true;
                        } else {
                            if (operator != null && operator == operatorValue + 1) {
                                trial++;
                                operator = 1;
                            }
                            grrDataDto.setOperator(operator.toString());
                            grrDataDto.setTrial(trial.toString());
                            if (k - (operatorValue * trialValue) > 0) {
                                if (!oldIncludeIds.contains(grrTestData.getId())) {
                                    grrDataDto.setOperator("");
                                    grrDataDto.setTrial("");
                                    isMore = true;
                                }
                            }
                        }
                        List<BaseDto> testItemNameList = Lists.newLinkedList();
                        for (TestItem testItem : grrTestData.getTestItems()) {
                            String itemName = testItem.getName();
                            if (itemNameTemp != null) {
                                if (itemNameTemp.equals(itemName) && itemNameCheckedLists.contains(itemName)) {
                                    baseDtoResult = new BaseDto();
                                    baseDtoResult.setKey(itemName);
                                    baseDtoResult.setValue(testItem.getTestedValue());
                                    testItemNameList.add(baseDtoResult);
                                    break;
                                }
                            } else {
                                if (!itemNameCheckedLists.contains(itemName)) {
                                    continue;
                                }
                                if (testItemNameList.size() == itemNameCheckedLists.size()) {
                                    break;
                                }
                                baseDtoResult = new BaseDto();
                                baseDtoResult.setKey(itemName);
                                baseDtoResult.setValue(testItem.getTestedValue());
                                testItemNameList.add(baseDtoResult);
                            }
                        }

                        grrDataDto.setColValueDtoList(testItemNameList);
                        k++;

                        if (grrDataDtoNormalList.size() >= total){
                            grrDataDto.setOperator("");
                            grrDataDto.setTrial("");
                            grrDataDto.setCheck(false);
                            grrDataDtoMoreList.add(grrDataDto);
                            isMore = false;
                        } else {
                            if (isMore) {
                                grrDataDto.setCheck(false);
                                grrDataDtoMoreList.add(grrDataDto);
                                isMore = false;
                            } else {
                                operator++;
                                grrDataDto.setCheck(true);
                                grrDataDtoNormalList.add(grrDataDto);
                            }
                        }
                    }
                    partSum++;
                }
                Map<String, List<GRRDataDto>> snAndOperatorMap = new LinkedHashMap<>();
                for (GRRDataDto grrDataDto : grrDataDtoNormalList) {
                    String snAndOp = grrDataDto.getPart() + grrDataDto.getOperator();
                    if (!snAndOperatorMap.containsKey(snAndOp)) {
                        List<GRRDataDto> grrDataDtoList1 = Lists.newLinkedList();
                        grrDataDtoList1.add(grrDataDto);
                        snAndOperatorMap.put(snAndOp, grrDataDtoList1);
                    } else {
                        snAndOperatorMap.get(snAndOp).add(grrDataDto);
                    }
                }

                for (String key : snAndOperatorMap.keySet()) {
                    grrDataDtoList.addAll(snAndOperatorMap.get(key));
                }
                if (grrDataDtoMoreList != null && !grrDataDtoMoreList.isEmpty()) {
                    snAndOperatorMap = new LinkedHashMap<>();
                    for (GRRDataDto grrDataDto : grrDataDtoMoreList) {
                        String snAndOp = grrDataDto.getPart() + grrDataDto.getOperator();
                        if (!snAndOperatorMap.containsKey(snAndOp)) {
                            List<GRRDataDto> grrDataDtoList1 = Lists.newLinkedList();
                            grrDataDtoList1.add(grrDataDto);
                            snAndOperatorMap.put(snAndOp, grrDataDtoList1);
                        } else {
                            snAndOperatorMap.get(snAndOp).add(grrDataDto);
                        }
                    }
                    for (String key : snAndOperatorMap.keySet()) {
                        grrDataDtoList.addAll(snAndOperatorMap.get(key));
                    }
                }
            } else {
                for (String key : partMap.keySet()) {
                    List<GRRTestData> valueMap = partMap.get(key);
                    Integer trial = 1, operator = 1, k = 1;
                    for (GRRTestData grrTestData : valueMap) {
                        GRRDataDto grrDataDto = new GRRDataDto();
                        grrDataDto.setPart(key);
                        grrDataDto.setId(grrTestData.getId());
                        if (oldExcludeIds.contains(grrTestData.getId())) {
                            grrDataDto.setOperator("");
                            grrDataDto.setTrial("");
                            isMore = true;
                        } else {
                            if (trial != null && trial == trialValue + 1) {
                                operator++;
                                trial = 1;
                            }
                            grrDataDto.setOperator(operator.toString());
                            grrDataDto.setTrial(trial.toString());
                            if (k - (operatorValue * trialValue) > 0) {
                                if (!oldIncludeIds.contains(grrTestData.getId())) {
                                    grrDataDto.setOperator("");
                                    grrDataDto.setTrial("");
                                    isMore = true;
                                }
                            }
                        }

                        List<BaseDto> testItemNameList = Lists.newLinkedList();
                        for (TestItem testItem : grrTestData.getTestItems()) {
                            String itemName = testItem.getName();
                            if (itemNameTemp != null) {
                                if (itemNameTemp.equals(itemName) && itemNameCheckedLists.contains(itemName)) {
                                    baseDtoResult = new BaseDto();
                                    baseDtoResult.setKey(itemName);
                                    baseDtoResult.setValue(testItem.getTestedValue());
                                    testItemNameList.add(baseDtoResult);
                                    break;
                                }
                            } else {
                                if (!itemNameCheckedLists.contains(itemName)) {
                                    continue;
                                }
                                if (testItemNameList.size() == itemNameCheckedLists.size()) {
                                    break;
                                }
                                baseDtoResult = new BaseDto();
                                baseDtoResult.setKey(itemName);
                                baseDtoResult.setValue(testItem.getTestedValue());
                                testItemNameList.add(baseDtoResult);
                            }
                        }
                        grrDataDto.setColValueDtoList(testItemNameList);
                        k++;
                        if (grrDataDtoNormalList.size() >= total){
                            grrDataDto.setOperator("");
                            grrDataDto.setTrial("");
                            grrDataDto.setCheck(false);
                            grrDataDtoMoreList.add(grrDataDto);
                            isMore = false;
                        } else {
                            if (isMore) {
                                grrDataDto.setCheck(false);
                                grrDataDtoMoreList.add(grrDataDto);
                                isMore = false;
                            } else {
                                trial++;
                                grrDataDto.setCheck(true);
                                grrDataDtoNormalList.add(grrDataDto);
                            }
                        }
                    }
                    partSum++;
                }
                grrDataDtoList.addAll(grrDataDtoNormalList);
                grrDataDtoList.addAll(grrDataDtoMoreList);
            }
        }

        return grrDataDtoList;
    }

    @Override
    public GRRResultDto searchGRRResult(Map<String, Object> searchParams) {
        GRRResultDto resultDto = this.getSubGRRResult(searchParams);
        //cache source and anova
        GRRAnalysisParamDto grrAnalysisParamDto = this.searchGRRTestItem(searchParams);
        List<GRRAnovaDto> grrAnovaDtoList = searchGRRAnova(searchParams, grrAnalysisParamDto);
        List<GRRSourceDto> grrSourceDtoList = searchGRRSource(searchParams, grrAnalysisParamDto);
        resultDto.setGrrAnovaDtoList(grrAnovaDtoList);
        resultDto.setGrrSourceDtoList(grrSourceDtoList);
        return resultDto;
    }

    @Override
    public List<GRRExportResultDto> searchGRRExportResult(Map<String, Object> searchParams) {
        List<GRRExportResultDto> grrExportResultDtoList = Lists.newLinkedList();
        List<GRRSummaryDto> grrSummaryDtoList = this.searchGRRSummaryForExport(searchParams);
        DateTimeFormatter format = DateTimeFormat.forPattern("yyyyMMddHHmmss");
        DateTimeFormatter format1 = DateTimeFormat.forPattern("yyyy/MM/dd");
        String projectName = (String) searchParams.get("projectName");
        DateTime now = new DateTime();
        String time = now.toString(format1);
        String fix = now.toString(format);
        String loginName = (String) searchParams.get(Constant.GLOBAL_LOGIN_NAME);
        int j = 0;
        for (int i = 0; i < grrSummaryDtoList.size(); i++) {
            String grr = grrSummaryDtoList.get(i).getGrr();
            if (grr == null || (Constant.GLOBAL_NAN).equals(grr) || ("Infinity").equals(grr) || grr.equals("-")) {
                continue;
            }
            j++;
            GRRExportParamDto grrExportParamDto = new GRRExportParamDto();
            grrExportParamDto.setTestItemName(grrSummaryDtoList.get(i).getItemName());
            grrExportParamDto.setUsl(grrSummaryDtoList.get(i).getUsl());
            grrExportParamDto.setLsl(grrSummaryDtoList.get(i).getLsl());
            grrExportParamDto.setTolerance(grrSummaryDtoList.get(i).getTolerance());
            String operator = Math.round((Double) searchParams.get(Constant.GRR_OPERATOR_VALUE)) + "";
            String sn = Math.round((Double) searchParams.get(Constant.GRR_PART_VALUE)) + "";
            String trial = Math.round((Double) searchParams.get(Constant.GRR_TRIAL_VALUE)) + "";
            grrExportParamDto.setOperatorCount(operator);
            grrExportParamDto.setSnCount(sn);
            grrExportParamDto.setTrialCount(trial);
            grrExportParamDto.setExportTime(time);
            grrExportParamDto.setPerformedBy(loginName);

            GRRExportResultDto grrExportResultDto = new GRRExportResultDto();
            searchParams.put(Constant.GLOBAL_ITEM_NAME, grrSummaryDtoList.get(i).getItemName());

            GRRResultDto grrResultDto = this.searchGRRResult(searchParams);

            grrExportResultDto.setGrrDataDtoList(grrResultDto.getGrrDataDtoList());
            grrExportResultDto.setGrrAnovaDtoList(grrResultDto.getGrrAnovaDtoList());
            grrExportResultDto.setGrrSourceDtoList(grrResultDto.getGrrSourceDtoList());
            grrExportResultDto.setGrrStatisticDataDtoList(grrResultDto.getGrrStatisticDataDtoList());
            grrExportResultDto.setGrrExportParamDto(grrExportParamDto);
            if (j == 1) {
                grrExportResultDto.setGrrSummaryDtoList(grrSummaryDtoList);
            }

            String charts[] = {Constant.GRR_XBAR_TYPE, Constant.GRR_R_TYPE, Constant.GRR_RESPONSE_OPERATOR, Constant.GRR_RESPONSE_PART, Constant.GRR_CONTRIBUTION_TYPE, Constant.GRR_INTERACTION_TYPE};
            List<String> imageList = Lists.newLinkedList();
            for (int k = 0; k < charts.length; k++) {
                StringBuilder sb1 = new StringBuilder();
                sb1.append("export_").append(projectName).append("_")
                        .append(loginName).append("_").append(grrSummaryDtoList.get(i).getItemName()).append("_").append(charts[k]).append("_").append(fix)
                        .append(".").append("jpg");
                String imgPath = ApplicationUtil.getProjectPathWithSeparator() + "exports/temp/";
                File file = new File(imgPath);
                if (!file.exists() && !file.isDirectory()) {
                    file.mkdir();
                }
                imgPath += sb1.toString();
                imageList.add(imgPath);
            }
            grrExportResultDto.setImgPaths(imageList);
            grrExportResultDtoList.add(grrExportResultDto);
        }
        return grrExportResultDtoList;
    }

    @Override
    public List<GRRSummaryDto> searchGRRSummaryForExport(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null || searchParams.get(Constant.GRR_NAME) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        List<GRRSummary> grrSummaryList = this.searchCacheGRRSummarys(searchParams);
        List<GRRSummaryDto> resultDtoList = Lists.newLinkedList();
        if (grrSummaryList != null && !grrSummaryList.isEmpty()) {

            PSGRRDto psGRRDto = projectService.findPSGRRByProject((String) searchParams.get(Constant.GLOBAL_PROJECT_ID));
            GRRItemDto grrItemDto = this.searchGRRItem(searchParams);

            Integer operatorValue = Integer.valueOf(grrItemDto.getOperatorValue());
            Integer trialValue = Integer.valueOf(grrItemDto.getTrialValue());
            Integer partValue = Integer.valueOf(grrItemDto.getPartValue());

            searchParams.put(Constant.GRR_OPERATOR_VALUE, Double.valueOf(operatorValue));
            searchParams.put(Constant.GRR_PART_VALUE, Double.valueOf(partValue));
            searchParams.put(Constant.GRR_TRIAL_VALUE, Double.valueOf(trialValue));
            searchParams.put(Constant.GRR_SIGMA_VALUE, Double.valueOf(StringUtils.isNumeric(psGRRDto.getSigma()) ? psGRRDto.getSigma() : Constant.GLOBAL_NAN));
            searchParams.put(Constant.GRR_RULE_VALUE, psGRRDto.getRule());
            searchParams.put(Constant.GRR_MODEL_VALUE, psGRRDto.getModel());
            List<String> itemNameCheckedLists = Lists.newLinkedList();
            if (searchParams.containsKey(Constant.GRR_EXPORT_ITEM_NAMES)) {
                itemNameCheckedLists = mapper.fromJson((String) searchParams.get(Constant.GRR_EXPORT_ITEM_NAMES), List.class);
            }

            for (GRRSummary grrSummary : grrSummaryList) {
                if (itemNameCheckedLists.contains(grrSummary.getItemName())) {
                    GRRSummaryDto grrSummaryDto = new GRRSummaryDto();
                    BeanMapper.copy(grrSummary, grrSummaryDto);
                    resultDtoList.add(grrSummaryDto);
                }
            }
        } else {
            resultDtoList = analysisService.analyseGRRSummary(searchParams, this.searchGRRTestItems(searchParams));
            saveGRRSummary(resultDtoList);
        }
        return resultDtoList;
    }

    @Override
    public List<GRRSummaryDto> searchGRRSummary(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null || searchParams.get(Constant.GRR_NAME) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        List<GRRSummary> grrSummaryList = this.searchCacheGRRSummarys(searchParams);
        List<GRRSummaryDto> resultDtoList = Lists.newLinkedList();
        if (grrSummaryList != null && !grrSummaryList.isEmpty()) {
            for (GRRSummary grrSummary : grrSummaryList) {
                GRRSummaryDto grrSummaryDto = new GRRSummaryDto();
                BeanMapper.copy(grrSummary, grrSummaryDto);
                resultDtoList.add(grrSummaryDto);
            }
        } else {
            resultDtoList = analysisService.analyseGRRSummary(searchParams, this.searchGRRTestItems(searchParams));
            saveGRRSummary(resultDtoList);
        }
        return resultDtoList;
    }

    @Override
    public GRRSummaryDto refreshGRRSummary(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null || searchParams.get(Constant.GRR_NAME) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        GRRSummaryDto grrSummaryDto = new GRRSummaryDto();
        List<GRRAnalysisParamDto> grrAnalysisParamDtoList = Lists.newLinkedList();
        grrAnalysisParamDtoList.add(this.searchGRRTestItem(searchParams));
        List<GRRSummaryDto>  grrSummaryList = analysisService.analyseGRRSummary(searchParams, grrAnalysisParamDtoList);
        if (grrSummaryList != null && !grrSummaryList.isEmpty()) {
            grrSummaryDto = grrSummaryList.get(0);
        }
        return grrSummaryDto;
    }

    @Override
    public GRRResultDto refreshGRRResult(Map<String, Object> searchParams) {
        GRRResultDto resultDto = this.getSubGRRResult(searchParams);
        GRRAnalysisParamDto grrAnalysisParamDto = this.searchGRRTestItem(searchParams);
        Map<String, Object> grrAnovaDtoAndSourceDto = analysisService.analyseGRRAnovaAndSource(searchParams, grrAnalysisParamDto);
        List<GRRAnovaDto> grrAnovaDtoList = (List<GRRAnovaDto>) grrAnovaDtoAndSourceDto.get(Constant.GRR_ANOVA_VALUE);
        List<GRRSourceDto> grrSourceDtoList = (List<GRRSourceDto>) grrAnovaDtoAndSourceDto.get(Constant.GRR_SOURCE_VALUE);

        resultDto.setGrrAnovaDtoList(grrAnovaDtoList);
        resultDto.setGrrSourceDtoList(grrSourceDtoList);

        return resultDto;
    }

    @Override
    public void saveGRRSummary(List<GRRSummaryDto> grrSummaryDtoList) {
        if (grrSummaryDtoList == null || grrSummaryDtoList.isEmpty()) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

        List<GRRSummary> grrSummaryList = Lists.newLinkedList();
        for (GRRSummaryDto grrSummaryDto : grrSummaryDtoList) {
            GRRSummary grrSummary = new GRRSummary();
            BeanMapper.copy(grrSummaryDto, grrSummary);
            grrSummaryList.add(grrSummary);
        }

        logger.debug("Saving grrSummary:{}", grrSummaryList.size());
        grrSummaryDao.save(grrSummaryList);
        logger.info("Save done,grrSummary = {}", grrSummaryList.size());
    }

    @Override
    public void deleteGRRSummary(Map<String, Object> searchParams) {
        List<GRRSummary> grrSummaryList = this.searchCacheGRRSummarys(searchParams);
        if (grrSummaryList != null && !grrSummaryList.isEmpty()) {
            grrSummaryDao.delete(grrSummaryList);
        }
    }

    @Override
    public void saveGRRAnova(List<GRRAnovaDto> grrAnovaDtoList) {
        if (grrAnovaDtoList == null || grrAnovaDtoList.isEmpty()) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        List<GRRAnova> grrAnovaList = Lists.newLinkedList();
        for (GRRAnovaDto grrAnovaDto : grrAnovaDtoList) {
            GRRAnova grrAnova = new GRRAnova();
            BeanMapper.copy(grrAnovaDto, grrAnova);
            grrAnovaList.add(grrAnova);
        }

        logger.debug("Saving grrAnova:{}", grrAnovaList.size());
        grrAnovaDao.save(grrAnovaList);
        logger.info("Save done,grrAnova = {}", grrAnovaList.size());
    }

    @Override
    public void deleteGRRAnova(Map<String, Object> searchParams) {
        List<GRRAnova> grrAnovaList = this.searchCacheGRRAnovas(searchParams);
        if (grrAnovaList != null && !grrAnovaList.isEmpty()) {
            grrAnovaDao.delete(grrAnovaList);
        }
    }

    @Override
    public List<GRRAnovaDto> searchGRRAnova(Map<String, Object> searchParams, GRRAnalysisParamDto grrAnalysisParamDto) {
        List<GRRAnova> grrAnovaList = this.searchCacheGRRAnovas(searchParams);
        List<GRRAnovaDto> grrAnovaDtoList = Lists.newLinkedList();
        if (grrAnovaList != null && !grrAnovaList.isEmpty()) {
            for (GRRAnova grrAnova : grrAnovaList) {
                GRRAnovaDto grrAnovaDto = new GRRAnovaDto();
                BeanMapper.copy(grrAnova, grrAnovaDto);
                grrAnovaDtoList.add(grrAnovaDto);
            }
        } else {
            Map<String, Object> grrAnovaDtoAndSourceDto = analysisService.analyseGRRAnovaAndSource(searchParams, grrAnalysisParamDto);
            grrAnovaDtoList = (List<GRRAnovaDto>) grrAnovaDtoAndSourceDto.get(Constant.GRR_ANOVA_VALUE);
            saveGRRAnova(grrAnovaDtoList);
        }

        return grrAnovaDtoList;
    }

    @Override
    public void saveGRRSource(List<GRRSourceDto> grrSourceDtoList) {
        if (grrSourceDtoList == null || grrSourceDtoList.isEmpty()) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

        List<GRRSource> grrSourceList = Lists.newLinkedList();
        for (GRRSourceDto grrSourceDto : grrSourceDtoList) {
            GRRSource grrSource = new GRRSource();
            BeanMapper.copy(grrSourceDto, grrSource);
            grrSourceList.add(grrSource);
        }

        logger.debug("Saving grrSource:{}", grrSourceList.size());
        grrSourceDao.save(grrSourceList);
        logger.info("Save done,grrSource = {}", grrSourceList.size());
    }

    @Override
    public void deleteGRRSource(Map<String, Object> searchParams) {
        List<GRRSource> grrSourceList = this.searchCacheGRRSources(searchParams);
        if (grrSourceList != null && !grrSourceList.isEmpty()) {
            grrSourceDao.delete(grrSourceList);
        }
    }

    @Override
    public List<GRRSourceDto> searchGRRSource(Map<String, Object> searchParams, GRRAnalysisParamDto grrAnalysisParamDto) {
        List<GRRSource> grrSourceList = this.searchCacheGRRSources(searchParams);
        List<GRRSourceDto> grrSourceDtoList = Lists.newLinkedList();

        if (grrSourceList != null && !grrSourceList.isEmpty()) {
            String grrSigma = null;
            String partSigma = null;
            for (int i =0; i <  grrSourceList.size(); i++) {
                GRRSource grrSource = grrSourceList.get(i);
                GRRSourceDto grrSourceDto = new GRRSourceDto();
                BeanMapper.copy(grrSourceList.get(i), grrSourceDto);
                if (grrSource.getKeyValue().equals(Constant.GRR_SOURCE_GAGE_RR)) {
                    grrSigma = grrSource.getSigma();
                }
                if (grrSource.getKeyValue().equals(Constant.GRR_SOURCE_PART)) {
                    partSigma = grrSource.getSigma();
                }
                if (i == grrSourceList.size() - 1) {
                    grrSourceDto.setDistincCategories(getDistinctGategories(partSigma, grrSigma));
                }
                grrSourceDtoList.add(grrSourceDto);
            }
        } else {
            Map<String, Object> grrAnovaDtoAndSourceDto = analysisService.analyseGRRAnovaAndSource(searchParams, grrAnalysisParamDto);
            grrSourceDtoList = (List<GRRSourceDto>) grrAnovaDtoAndSourceDto.get(Constant.GRR_SOURCE_VALUE);
            saveGRRSource(grrSourceDtoList);
        }

        return grrSourceDtoList;
    }

    @Override
    public void deleteGRRTestData(String grrName, String projectId) {
        logger.info("Delete grr testData: projectId={}, grrName={}", projectId, grrName);
        if (StringUtils.isBlank(projectId)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Map<String, Object> searchParams = new HashMap<>();
        searchParams.put(Constant.GRR_NAME, grrName);
        searchParams.put(Constant.GLOBAL_PROJECT_ID, projectId);

        grrTestDataDao.findAllAndRemove(searchParams);
        this.deleteGRRSummary(searchParams);
        this.deleteGRRAnova(searchParams);
        this.deleteGRRSource(searchParams);
        this.deleteGRRItem(searchParams);

    }

    @Override
    public void checkGRRTestData(Map<String, Object> searchParams, List<GRRTestData> grrTestDataList) {
        if (grrTestDataList == null || grrTestDataList.isEmpty() || searchParams == null || !searchParams.containsKey(Constant.GRR_OPERATOR_VALUE)
                || !searchParams.containsKey(Constant.GRR_PART_VALUE) || !searchParams.containsKey(Constant.GRR_TRIAL_VALUE)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Integer partValue = Integer.valueOf((String) searchParams.get(Constant.GRR_PART_VALUE));
        Integer operatorValue = Integer.valueOf((String) searchParams.get(Constant.GRR_OPERATOR_VALUE));
        Integer trialValue = Integer.valueOf((String) searchParams.get(Constant.GRR_TRIAL_VALUE));

        Integer partNumber = operatorValue * trialValue;
        //Integer total = partValue * operatorValue * trialValue;

        BaseDto part = (BaseDto) searchParams.get(Constant.GRR_PART_KEY);
        BaseDto group1 = (BaseDto) searchParams.get(Constant.GRR_GROUP1_KEY);
        BaseDto group2 = (BaseDto) searchParams.get(Constant.GRR_GROUP2_KEY);
        BaseDto dimension = (BaseDto) searchParams.get(Constant.GRR_DIMENSION_KEY);
        String dimensionValue = (String) searchParams.get(Constant.GRR_DIMENSION_VALUE);

        PSGRRDto psGRRDto = projectService.findPSGRRByProject((String) searchParams.get(Constant.GLOBAL_PROJECT_ID));
        Map<String, Integer> analysisKeysMap = new LinkedHashMap<>();
        Map<String, Integer> groupKeysMap = new LinkedHashMap<>();

        List<String> partList = Lists.newLinkedList();
        List<String> dimensionValueList = Lists.newLinkedList();
        String partKeyValue = null;
        String group1KeyValue = null;
        String group2KeyValue = null;
        String dimensionKeyValue = null;
        for (GRRTestData grrTestData : grrTestDataList) {
            if ((Boolean) part.getValue()) {
                partKeyValue = (String) grrTestData.getTestData().get(part.getKey());
            }
            if ((Boolean) group1.getValue()) {
                group1KeyValue = (String) grrTestData.getTestData().get(group1.getKey());
            }
            if ((Boolean) group2.getValue()) {
                group2KeyValue = (String) grrTestData.getTestData().get(group2.getKey());
            }
            if ((Boolean) dimension.getValue()) {
                dimensionKeyValue = (String) grrTestData.getTestData().get(dimension.getKey());
            }

            if (grrTestData.getDutAttributes() != null && !grrTestData.getDutAttributes().isEmpty()) {
                for (DUTAttribute dUTAttribute : grrTestData.getDutAttributes()) {
                    if (!(Boolean) part.getValue() && dUTAttribute.getAttributeName().equals(part.getKey())) {
                        partKeyValue = dUTAttribute.getAttributeValue();
                    } else if (!(Boolean) group1.getValue() && dUTAttribute.getAttributeName().equals(group1.getKey())) {
                        group1KeyValue = dUTAttribute.getAttributeValue();
                    } else if (StringUtils.isNotBlank(group2.getKey()) && !(Boolean) group2.getValue() && dUTAttribute.getAttributeName().equals(group2.getKey())) {
                        group2KeyValue = dUTAttribute.getAttributeValue();
                    } else if (StringUtils.isNotBlank(dimension.getKey()) && !(Boolean) dimension.getValue() && dUTAttribute.getAttributeName().equals(dimension.getKey())) {
                        dimensionKeyValue = dUTAttribute.getAttributeValue();
                    }
                }
            }

            String analysisKeys = null;
            String groupKeys = null;
            if (StringUtils.isNotBlank(group2KeyValue) && StringUtils.isNotBlank(dimensionKeyValue)) {
                analysisKeys = partKeyValue + Constant.GLOBAL_SEPARATOR + group1KeyValue + Constant.GLOBAL_SEPARATOR + group2KeyValue + Constant.GLOBAL_SEPARATOR + dimensionKeyValue;
                groupKeys = partKeyValue + Constant.GLOBAL_SEPARATOR + group1KeyValue + Constant.GLOBAL_SEPARATOR + group2KeyValue;
            } else if (StringUtils.isNotBlank(group2KeyValue) && StringUtils.isBlank(dimensionKeyValue)) {
                analysisKeys = partKeyValue + Constant.GLOBAL_SEPARATOR + group1KeyValue + Constant.GLOBAL_SEPARATOR + group2KeyValue;
            } else if (StringUtils.isBlank(group2KeyValue) && StringUtils.isNotBlank(dimensionKeyValue)) {
                analysisKeys = partKeyValue + Constant.GLOBAL_SEPARATOR + group1KeyValue + Constant.GLOBAL_SEPARATOR + dimensionKeyValue;
                groupKeys = partKeyValue + Constant.GLOBAL_SEPARATOR + group1KeyValue;
            }  else {
                analysisKeys = partKeyValue + Constant.GLOBAL_SEPARATOR + group1KeyValue;
            }

            if (!partList.contains(partKeyValue)) {
                partList.add(partKeyValue);
            }
            if (!dimensionValueList.contains(dimensionKeyValue)) {
                dimensionValueList.add(dimensionKeyValue);
            }
            /*if (!stationList.contains(station)) {
                stationList.add(station);
            }*/
            if (!analysisKeysMap.containsKey(analysisKeys)) {
                analysisKeysMap.put(analysisKeys, 1);
            } else {
                analysisKeysMap.put(analysisKeys, analysisKeysMap.get(analysisKeys) + 1);
            }

            if (!groupKeysMap.containsKey(groupKeys)) {
                groupKeysMap.put(groupKeys, 1);
            } else {
                groupKeysMap.put(groupKeys, groupKeysMap.get(groupKeys) + 1);
            }


            if (searchParams.containsKey(Constant.GRR_START_TIME)) {
                grrTestData.setGrrStartTime((Date) searchParams.get(Constant.GRR_START_TIME));
            }

            if (searchParams.containsKey(Constant.GRR_END_TIME)) {
                grrTestData.setGrrEndTime((Date) searchParams.get(Constant.GRR_END_TIME));
            }
        }

        if (partList == null || partList.isEmpty() || partList.size() < partValue) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_GRR_DATA_SN_COUNT_ERROR + (partValue - partList.size()));
        }

        List<String> errorAnalysisKeys = Lists.newLinkedList();
        if (Model.SLOT.getCode().equals(psGRRDto.getModel())) {
            String[] testStrategy = dimensionValue.split(";");
            List<String> errorDimensionValues = Lists.newLinkedList();
            Map<String, Integer> groupKeysMap1 = new LinkedHashMap<>();

            for (String ts : testStrategy) {
                String[] dimensionValues = ts.split(",");
                for (int i = 0; i < dimensionValues.length; i++) {
                    if (!dimensionValueList.contains(dimensionValues[i])) {
                        errorDimensionValues.add(dimensionValues[i]);
                    }
                    for (String key : groupKeysMap.keySet()) {
                        key = key + Constant.GLOBAL_SEPARATOR + dimensionValues[i];
                        if (!groupKeysMap1.containsKey(key)) {
                            groupKeysMap1.put(key, 1);
                        } else {
                            groupKeysMap1.put(key, groupKeysMap1.get(key) + 1);
                        }
                    }
                }
                if (!errorDimensionValues.isEmpty()) {
                    throw new ApplicationException(ExceptionMessages.EXCEPTION_GRR_DATA_DIMENSION_INCOMPLETE + errorDimensionValues);
                }
            }

          /*  if (analysisKeysMap.keySet().size() < groupTotal) {
                throw new ApplicationException(ExceptionMessages.EXCEPTION_GRR_DATA_GROUP_COUNT_ERROR + (groupTotal - analysisKeysMap.keySet().size()));
            }*/
            /*for (String key : analysisKeysMap.keySet()) {
                if (analysisKeysMap.get(key) == null || analysisKeysMap.get(key) < trialValue) {
                    errorAnalysisKeys.add(key.replace(Constant.GLOBAL_SEPARATOR, "_"));
                }
            }*/
            int lackOfTotal = 0;
            for (String key : groupKeysMap1.keySet()) {
                if (!analysisKeysMap.keySet().contains(key)) {
                    lackOfTotal++;
                }
                if (analysisKeysMap.get(key) == null || analysisKeysMap.get(key) < trialValue) {
                    errorAnalysisKeys.add(key.replace(Constant.GLOBAL_SEPARATOR, "_"));
                }
            }

            if (lackOfTotal != 0) {
                throw new ApplicationException(ExceptionMessages.EXCEPTION_GRR_DATA_GROUP_COUNT_ERROR + lackOfTotal);
            }

            if (!errorAnalysisKeys.isEmpty()) {
                throw new ApplicationException(ExceptionMessages.EXCEPTION_GRR_DATA_SN_TYPE_ERROR + errorAnalysisKeys);
            }

        } else {
            for (String key : analysisKeysMap.keySet()) {
                if (analysisKeysMap.get(key) == null || analysisKeysMap.get(key) < partNumber) {
                    errorAnalysisKeys.add(key.replace(Constant.GLOBAL_SEPARATOR, "_"));
                }
            }
            if (!errorAnalysisKeys.isEmpty()) {
                throw new ApplicationException(ExceptionMessages.EXCEPTION_GRR_DATA_SN_TYPE_ERROR + errorAnalysisKeys);
            }
        }
    }

    @Override
    public void saveGRRItem(GRRItemDto grrItemDto) {
        if (grrItemDto == null || StringUtils.isBlank(grrItemDto.getGrrName())) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

        GRRItem grrItem = grrItemDao.findByGrrName(grrItemDto.getGrrName());

        if (grrItem != null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_OBJECT_ALREADY_EXISTS);
        }

        grrItem = new GRRItem();
        BeanMapper.copy(grrItemDto, grrItem);

        logger.debug("Saving GRRItem:{}", grrItemDto);
        grrItemDao.save(grrItem);
        logger.info("Save done,GRRItem = {}", grrItemDto.getGrrName());
    }

    @Override
    public void updateGRRItem(GRRItemDto grrItemDto) {
        if (grrItemDto == null || grrItemDto.getId() == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

        GRRItem grrItem = grrItemDao.findById(grrItemDto.getId());
        if (grrItem == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_OBJECT_DOES_NOT_EXIST);
        }
        BeanUtil.copyBeanPropertiesWithoutNull(grrItemDto, grrItem);

        logger.debug("Updating GRRItem:{}", grrItemDto);
        grrItemDao.save(grrItem);
        logger.info("Update done, GRRItem={}", grrItem.getGrrName());
    }

    @Override
    public void deleteGRRItem(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null
                || searchParams.get(Constant.GRR_NAME) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

        String grrName = (String) searchParams.get("grrName");
        String projectId = (String) searchParams.get("projectId");
        logger.debug("Searching GRRItem with{},{}", grrName, projectId);
        GRRItem grrItem = grrItemDao.findByGrrNameAndProjectId(grrName, Long.valueOf(projectId));
        if (grrItem != null) {
            grrItemDao.delete(grrItem);
        }
    }

    @Override
    public void updateCacheGRRItem(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null
                || searchParams.get(Constant.GRR_NAME) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

        String projectId = (String) searchParams.get(Constant.GLOBAL_PROJECT_ID);
        String grrName = (String) searchParams.get(Constant.GRR_NAME);
        String stationAndSlot = this.getAnalysisKeys(searchParams);
        String searchKey = projectId + "," + grrName + "," + stationAndSlot;
        GRRItem grrItem = grrItemDao.findByGrrNameAndProjectId(grrName, Long.valueOf(projectId));
        if (grrItem == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_OBJECT_DOES_NOT_EXIST);
        }
        List<BaseDto> oldItemValueIncludeIdList = Lists.newLinkedList();
        List<BaseDto> oldItemValueExcludeIdList = Lists.newLinkedList();

        List<String> oldIncludeIds = Lists.newLinkedList();
        List<String> oldExcludeIds = Lists.newLinkedList();
        if (searchParams.get(Constant.GRR_ITEM_NAME_IN) != null && searchParams.get(Constant.GRR_ITEM_NAME_EX) != null) {
            if (StringUtils.isNotBlank(grrItem.getIncludeIds())) {
                oldItemValueIncludeIdList = mapper.fromJson(grrItem.getIncludeIds(), mapper.contructCollectionType(List.class, BaseDto.class));
                oldItemValueExcludeIdList = mapper.fromJson(grrItem.getExcludeIds(), mapper.contructCollectionType(List.class, BaseDto.class));
                for (int i = 0; i < oldItemValueIncludeIdList.size(); i++) {
                    BaseDto oldIncludeIdDto = oldItemValueIncludeIdList.get(i);
                    BaseDto oldExcludeIdDto = oldItemValueExcludeIdList.get(i);
                    if (oldIncludeIdDto.getKey().equals(searchKey)) {
                        oldIncludeIds = mapper.fromJson((String) oldIncludeIdDto.getValue(), List.class);
                        oldExcludeIds = mapper.fromJson((String) oldExcludeIdDto.getValue(), List.class);
                        if (searchParams.get(Constant.GRR_ITEM_NAME_EX) != null) {
                            List<String> newExcludeIds = mapper.fromJson((String) searchParams.get(Constant.GRR_ITEM_NAME_EX), List.class);
                            List<String> newIncludeIds = mapper.fromJson((String) searchParams.get(Constant.GRR_ITEM_NAME_IN), List.class);
                            if (newExcludeIds != null && !newExcludeIds.isEmpty() && newIncludeIds != null && !newIncludeIds.isEmpty()) {
                                oldIncludeIds.addAll(newIncludeIds);
                                oldExcludeIds.addAll(newExcludeIds);
                                List<String> ignore = Lists.newLinkedList();
                                for (int k = 0; k < oldIncludeIds.size(); k++) {
                                    String in = oldIncludeIds.get(k);
                                    if (oldExcludeIds.contains(in)) {
                                        ignore.add(in);
                                    }
                                }
                                oldExcludeIds.removeAll(ignore);
                                oldIncludeIds.removeAll(ignore);

                                BaseDto includeIdDto = new BaseDto();
                                includeIdDto.setKey(searchKey);
                                includeIdDto.setValue(mapper.toJson(oldIncludeIds));
                                oldItemValueIncludeIdList.add(includeIdDto);

                                BaseDto excludIdDto = new BaseDto();
                                excludIdDto.setKey(searchKey);
                                excludIdDto.setValue(mapper.toJson(oldExcludeIds));
                                oldItemValueExcludeIdList.add(excludIdDto);
                            }
                        }
                        oldItemValueIncludeIdList.remove(oldIncludeIdDto);
                        oldItemValueExcludeIdList.remove(oldExcludeIdDto);
                        break;
                    }
                }
            } else {
                if (searchParams.get(Constant.GRR_ITEM_NAME_EX) != null) {
                    List<String> newExcludeIds = mapper.fromJson((String) searchParams.get(Constant.GRR_ITEM_NAME_EX), List.class);
                    List<String> newIncludeIds = mapper.fromJson((String) searchParams.get(Constant.GRR_ITEM_NAME_IN), List.class);
                    if (newExcludeIds != null && !newExcludeIds.isEmpty() && newIncludeIds != null && !newIncludeIds.isEmpty()) {
                        BaseDto includeIdDto = new BaseDto();
                        includeIdDto.setKey(searchKey);
                        includeIdDto.setValue(mapper.toJson(newIncludeIds));
                        oldItemValueIncludeIdList.add(includeIdDto);

                        BaseDto excludIdDto = new BaseDto();
                        excludIdDto.setKey(searchKey);
                        excludIdDto.setValue(mapper.toJson(newExcludeIds));
                        oldItemValueExcludeIdList.add(excludIdDto);
                    }
                }
            }
            if (!oldItemValueIncludeIdList.isEmpty()) {
                grrItem.setIncludeIds(mapper.toJson(oldItemValueIncludeIdList));
                grrItem.setExcludeIds(mapper.toJson(oldItemValueExcludeIdList));
            }
        }

        if (searchParams.get(Constant.GRR_ITEM_NAMES) != null) {
            List<String> itemNames = mapper.fromJson((String) searchParams.get(Constant.GRR_ITEM_NAMES), List.class);
            List<BaseDto> itemNameAllLists = mapper.fromJson(grrItem.getTestItemNames(), mapper.contructCollectionType(List.class, BaseDto.class));

            List<BaseDto> itemNameLists = Lists.newLinkedList();
            if (itemNameAllLists != null && !itemNameAllLists.isEmpty()) {
                for (BaseDto baseDto : itemNameAllLists) {
                    baseDto.setValue(false);
                    if (itemNames.contains(baseDto.getKey())) {
                        baseDto.setValue(true);
                    }
                    itemNameLists.add(baseDto);
                }
                grrItem.setTestItemNames(mapper.toJson(itemNameLists));
            }
        }

        grrItemDao.save(grrItem);
        logger.info("Update done, GRRItem={}", grrItem.getGrrName());
        this.deleteGRRSummary(searchParams);
        this.deleteGRRAnova(searchParams);
        this.deleteGRRSource(searchParams);
    }

    @Override
    public GRRItemDto searchGRRItem(Map<String, Object> searchParams) {
        if (!searchParams.containsKey("projectId") || !searchParams.containsKey("grrName")) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        String grrName = (String) searchParams.get("grrName");
        String projectId = (String) searchParams.get("projectId");
        logger.debug("Searching GRRItem with{},{}", grrName, projectId);

        GRRItem grrItem = grrItemDao.findByGrrNameAndProjectId(grrName, Long.valueOf(projectId));

        if (grrItem == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_OBJECT_DOES_NOT_EXIST);
        }

        logger.debug("Searching GRRItem:{}", grrItem.getGrrName());
        GRRItemDto grrItemDto = new GRRItemDto();
        BeanMapper.copy(grrItem, grrItemDto);

        return grrItemDto;
    }

    @Override
    public boolean checkGRRName(String grrName, String projectId) {
        if (StringUtils.isBlank(grrName) || StringUtils.isBlank(projectId) || !StringUtils.isNumeric(projectId)) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        boolean result = false;
        logger.debug("Checking GRRItem: {}, {}", grrName, projectId);
        GRRItem grrItem = grrItemDao.findByGrrNameAndProjectId(grrName, Long.valueOf(projectId));
        if (grrItem != null && !grrItem.getDelete()) {
            result = true;
        }

        return result;
    }

    @Override
    public GRRChartDto searchGRRChart(Map<String, Object> searchParams) {
        if (!searchParams.containsKey("projectId") || !searchParams.containsKey("grrName") || !searchParams.containsKey("itemName")) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

        GRRAnalysisParamDto paramDto = this.searchGRRTestItem(searchParams);

        GRRItemDto grrItemDto = this.searchGRRItem(searchParams);
        Integer operatorValue = Integer.valueOf(grrItemDto.getOperatorValue());
        Integer trialValue = Integer.valueOf(grrItemDto.getTrialValue());
        Integer partValue = Integer.valueOf(grrItemDto.getPartValue());

        searchParams.put(Constant.GRR_OPERATOR_VALUE, Double.valueOf(operatorValue));
        searchParams.put(Constant.GRR_PART_VALUE, Double.valueOf(partValue));
        searchParams.put(Constant.GRR_TRIAL_VALUE, Double.valueOf(trialValue));

        GRRChartDto resultDto = analysisService.analyseGRRChartData(searchParams, paramDto);

        return resultDto;
    }

    private List<GRRSummary> searchCacheGRRSummarys(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Map<String, Object> map = Maps.newHashMap();
        if (searchParams.get(Constant.GLOBAL_PROJECT_ID) != null) {
            map.put("EQ_projectId", searchParams.get(Constant.GLOBAL_PROJECT_ID));
        }

        if (searchParams.get(Constant.GRR_NAME) != null) {
            map.put("EQ_grrName", searchParams.get(Constant.GRR_NAME));
        }

        if (getStationAndSlot(searchParams) != null) {
            map.put("EQ_stationAndSlot", this.getAnalysisKeys(searchParams));
        }

        Map<String, SearchFilter> filters = SearchFilter.parse(map);
        Specification<GRRSummary> spec = DynamicSpecifications.bySearchFilter(filters.values(), GRRSummary.class);

        List<GRRSummary> grrSummaryList = grrSummaryDao.findAll(spec);
        return grrSummaryList;
    }

    private List<GRRAnova> searchCacheGRRAnovas(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Map<String, Object> map = Maps.newHashMap();
        if (searchParams.get(Constant.GLOBAL_PROJECT_ID) != null) {
            map.put("EQ_projectId", searchParams.get(Constant.GLOBAL_PROJECT_ID));
        }

        if (searchParams.get(Constant.GRR_NAME) != null) {
            map.put("EQ_grrName", searchParams.get(Constant.GRR_NAME));
        }

        if (getStationAndSlot(searchParams) != null) {
            map.put("EQ_stationAndSlot", this.getAnalysisKeys(searchParams));
        }
        if (searchParams.containsKey(Constant.GLOBAL_ITEM_NAME)) {
            map.put("EQ_itemName", searchParams.get(Constant.GLOBAL_ITEM_NAME));
        }

        Map<String, SearchFilter> filters = SearchFilter.parse(map);
        Specification<GRRAnova> spec = DynamicSpecifications.bySearchFilter(filters.values(), GRRAnova.class);

        List<GRRAnova> grrAnovaList = grrAnovaDao.findAll(spec);
        return grrAnovaList;
    }

    private List<GRRSource> searchCacheGRRSources(Map<String, Object> searchParams) {
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        Map<String, Object> map = Maps.newHashMap();
        if (searchParams.get(Constant.GLOBAL_PROJECT_ID) != null) {
            map.put("EQ_projectId", searchParams.get(Constant.GLOBAL_PROJECT_ID));
        }

        if (searchParams.get(Constant.GRR_NAME) != null) {
            map.put("EQ_grrName", searchParams.get(Constant.GRR_NAME));
        }

        if (getStationAndSlot(searchParams) != null) {
            map.put("EQ_stationAndSlot", this.getAnalysisKeys(searchParams));
        }

        if (searchParams.containsKey(Constant.GLOBAL_ITEM_NAME)) {
            map.put("EQ_itemName", searchParams.get(Constant.GLOBAL_ITEM_NAME));
        }
        Map<String, SearchFilter> filters = SearchFilter.parse(map);
        Specification<GRRSource> spec = DynamicSpecifications.bySearchFilter(filters.values(), GRRSource.class);

        List<GRRSource> grrSourceList = grrSourceDao.findAll(spec);
        return grrSourceList;
    }

    @Override
    @Deprecated
    public String getStationAndSlot(Map<String, Object> searchParams) {
        String stationId = "";
        String slot = "";
        if (searchParams.containsKey(Constant.GLOBAL_STATION_OR_SLOT)) {
            List<StationDto> stationDtoList = mapper.fromJson((String) searchParams.get(Constant.GLOBAL_STATION_OR_SLOT), mapper.contructCollectionType(List.class, StationDto.class));
            if (stationDtoList != null && !stationDtoList.isEmpty()) {
                for (int i = 0; i < stationDtoList.size(); i++) {
                    if (StringUtils.isNotBlank(stationDtoList.get(i).getStationId()) || stationDtoList.get(i).getStationId() == "") {
                        stationId = stationDtoList.get(i).getStationId();
                    }
                    if (stationDtoList.get(i).getSlotNos() != null && !stationDtoList.get(i).getSlotNos().isEmpty()) {
                        for (String slot1 : stationDtoList.get(i).getSlotNos()) {
                            slot += slot1 + ",";
                        }
                    }
                }
            }
        } else {
            return "";
        }
        slot = ("").equals(slot) ? "" : slot.substring(0, slot.length() - 1);
        if (("").equals(stationId) && ("").equals(slot)) {
            return "";
        } else if (!("").equals(stationId) && ("").equals(slot)) {
            return stationId;
        } else if (("").equals(stationId) && !("").equals(slot)) {
            return slot;
        }
        return stationId + "_" + slot;
    }

    @Override
    public String getAnalysisKeys(Map<String, Object> searchParams) {
        String groupKey = "";
        String dimenssion = "";
        if (searchParams.containsKey(Constant.GRR_ANALYSIS_KEYS)) {
            List<AnalysisKeyResultDto> analysisKeyResultDtoList = mapper.fromJson((String) searchParams.get(Constant.GRR_ANALYSIS_KEYS), mapper.contructCollectionType(List.class, AnalysisKeyResultDto.class));
            if (analysisKeyResultDtoList != null && !analysisKeyResultDtoList.isEmpty()) {
                for (int i = 0; i < analysisKeyResultDtoList.size(); i++) {
                    if (StringUtils.isNotBlank(analysisKeyResultDtoList.get(i).getGroupKey()) || analysisKeyResultDtoList.get(i).getGroupKey() == "") {
                        groupKey = analysisKeyResultDtoList.get(i).getGroupKey();
                    }
                    if (analysisKeyResultDtoList.get(i).getDimensionList() != null && !analysisKeyResultDtoList.get(i).getDimensionList().isEmpty()) {
                        for (String dimenssion1 : analysisKeyResultDtoList.get(i).getDimensionList()) {
                            dimenssion += dimenssion1 + ",";
                        }
                    }
                }
            }
        } else {
            return "";
        }
        dimenssion = ("").equals(dimenssion) ? "" : dimenssion.substring(0, dimenssion.length() - 1);
        if (("").equals(groupKey) && ("").equals(dimenssion)) {
            return "";
        } else if (!("").equals(groupKey) && ("").equals(dimenssion)) {
            return groupKey;
        } else if (("").equals(groupKey) && !("").equals(dimenssion)) {
            return dimenssion;
        }
        return groupKey + "_" + dimenssion;
    }


    @Override
    public void updatePSGRR(PSGRRDto psGRRDto) {
        if (psGRRDto == null || psGRRDto.getId() == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }

        PSGRR psgrr = new PSGRR();
        BeanMapper.copy(psGRRDto, psgrr);
        psGRRDao.save(psgrr);
        //clean cache
        Map<String, Object> searchParams = Maps.newHashMap();
        searchParams.put(Constant.GLOBAL_PROJECT_ID, String.valueOf(psGRRDto.getProjectId()));
        this.deleteGRRSummary(searchParams);
        this.deleteGRRAnova(searchParams);
        this.deleteGRRSource(searchParams);
    }

    private GRRResultDto getSubGRRResult(Map<String, Object> searchParams){
        if (searchParams == null || searchParams.get(Constant.GLOBAL_PROJECT_ID) == null
                || searchParams.get(Constant.GRR_NAME) == null || searchParams.get(Constant.GLOBAL_ITEM_NAME) == null) {
            throw new ApplicationException(ExceptionMessages.EXCEPTION_PARAMETER_INPUT_INVALID);
        }
        List<GRRDataDto> grrDataDtoList = this.searchGRRTestData(searchParams);
        GRRResultDto resultDto = new GRRResultDto();
        if (grrDataDtoList == null || grrDataDtoList.isEmpty()) {
            return resultDto;
        }
        String itemName = (String) searchParams.get(Constant.GLOBAL_ITEM_NAME);
        String trial = null;
        Map<String, List<BaseDto>> opAndTrirList = new LinkedHashMap<>();
        Map<String, List<BaseDto>> opList = new LinkedHashMap<>();
        BaseDto baseDtoResult = null;
        for (GRRDataDto grrDataDto : grrDataDtoList) {
            if (!grrDataDto.getCheck()) {
                continue;
            }
            String sn = grrDataDto.getPart();
            String operator = grrDataDto.getOperator();
            trial = grrDataDto.getTrial();
            String opAndTri = operator + "_" + trial;
            baseDtoResult = new BaseDto();
            BaseDto baseDtoResult1 = new BaseDto();
            baseDtoResult.setKey(sn);
            baseDtoResult1.setKey(sn);
            for (BaseDto baseDto : grrDataDto.getColValueDtoList()) {
                if (baseDto.getKey().equals(itemName)) {
                    String itemValue = (String) baseDto.getValue();
                    baseDtoResult.setValue(itemValue);
                    if (!opAndTrirList.containsKey(opAndTri)) {
                        List<BaseDto> colValueDtoList = Lists.newLinkedList();
                        colValueDtoList.add(baseDtoResult);
                        opAndTrirList.put(opAndTri, colValueDtoList);
                    } else {
                        opAndTrirList.get(opAndTri).add(baseDtoResult);
                    }

                    if (StringUtils.isBlankWithSpecialNumber(itemValue)) {
                        itemValue = Constant.GLOBAL_NAN;
                    }
                    baseDtoResult1.setValue(itemValue);
                    if (!opList.containsKey(operator)) {
                        List<BaseDto> itemValueList = Lists.newLinkedList();
                        itemValueList.add(baseDtoResult1);
                        opList.put(operator, itemValueList);
                    } else {
                        opList.get(operator).add(baseDtoResult1);
                    }
                    break;
                }
            }
        }
        //sub data
        List<GRRDataDto> grrDataDtoResultList = Lists.newLinkedList();
        for (String key : opAndTrirList.keySet()) {
            String operator = key.split("_")[0];
            trial = key.split("_")[1];
            GRRDataDto grrDataDto = new GRRDataDto();
            grrDataDto.setOperator(operator);
            grrDataDto.setTrial(trial);
            grrDataDto.setColValueDtoList(opAndTrirList.get(key));
            grrDataDtoResultList.add(grrDataDto);
        }

        List<GRRStatisticDataDto> grrStatisticDataDtoList = Lists.newLinkedList();
        Map<String, List<Double>> allSnList = new LinkedHashMap<>();
        for (String key : opList.keySet()) {
            List<BaseDto> itemValueList = opList.get(key);
            List<BaseDto> meanList = Lists.newLinkedList();
            List<BaseDto> rangList = Lists.newLinkedList();
            Map<String, List<Double>> snList = new LinkedHashMap<>();
            for (int i = 0; i < itemValueList.size(); i++) {
                String sn = itemValueList.get(i).getKey();
                Double itemValue = Double.valueOf((String) itemValueList.get(i).getValue());
                if (!snList.containsKey(sn)) {
                    List<Double> itemValueLists = Lists.newLinkedList();
                    itemValueLists.add(itemValue);
                    snList.put(sn, itemValueLists);
                } else {
                    snList.get(sn).add(itemValue);
                }

                if (!allSnList.containsKey(sn)) {
                    List<Double> itemValueLists = Lists.newLinkedList();
                    itemValueLists.add(itemValue);
                    allSnList.put(sn, itemValueLists);
                } else {
                    allSnList.get(sn).add(itemValue);
                }
                //every operator avg and rang
                if (i == itemValueList.size() - 1) {
                    double sum = 0;
                    for (String snKey : snList.keySet()) {
                        BaseDto baseDtoResult1 = new BaseDto();
                        BaseDto baseDtoResult2 = new BaseDto();

                        baseDtoResult1.setKey(snKey);
                        baseDtoResult2.setKey(snKey);

                        List<Double> snItemValueList = snList.get(snKey);
                        List<Double> snItemNormalList = Lists.newArrayList();
                        double[] itemValues = new double[snItemValueList.size()];
                        for (int j = 0; j < snItemValueList.size(); j++) {
                            itemValues[j] = snItemValueList.get(j);
                            if (!StringUtils.isBlankWithSpecialNumber(String.valueOf(itemValues[j]))) {
                                snItemNormalList.add(itemValues[j]);
                                sum += snItemValueList.get(j);
                            }
                        }
                        baseDtoResult1.setValue(getAverage(itemValues));
                        meanList.add(baseDtoResult1);
                        if (snItemNormalList.isEmpty()) {
                            baseDtoResult2.setValue("-");
                        } else {
                            baseDtoResult2.setValue(getRange(Collections.max(snItemNormalList), Collections.min(snItemNormalList)));
                        }
                        rangList.add(baseDtoResult2);
                    }
                    double[] resultValues = new double[meanList.size()];
                    for (int j = 0; j < meanList.size(); j++) {
                        if (("-").equals((String) meanList.get(j).getValue())) {
                            resultValues[j] = Double.valueOf(Constant.GLOBAL_NAN);
                        } else {
                            resultValues[j] = Double.valueOf((String) meanList.get(j).getValue());
                        }
                    }
                    String mean = getAverage(resultValues);
                    String rang = Double.toString(Math.pow(sum, 2));

                    GRRStatisticDataDto grrStatisticDataDto = new GRRStatisticDataDto();
                    grrStatisticDataDto.setMean(mean);
                    grrStatisticDataDto.setMeanList(meanList);
                    grrStatisticDataDto.setRangList(rangList);
                    grrStatisticDataDto.setRang(rang);
                    grrStatisticDataDtoList.add(grrStatisticDataDto);
                }
            }
        }
        //total range and avg
        GRRStatisticDataDto grrStatisticDataDto = new GRRStatisticDataDto();
        List<BaseDto> toatlMeanList = Lists.newLinkedList();
        List<BaseDto> toalRangList = Lists.newLinkedList();
        for (String snKey : allSnList.keySet()) {
            BaseDto baseDtoResult1 = new BaseDto();
            BaseDto baseDtoResult2 = new BaseDto();

            baseDtoResult1.setKey(snKey);
            baseDtoResult2.setKey(snKey);

            List<Double> allSnItemValueList = allSnList.get(snKey);
            List<Double> snItemNormalList = Lists.newArrayList();
            double[] itemValues = new double[Integer.valueOf(allSnItemValueList.size())];
            for (int j = 0; j < allSnItemValueList.size(); j++) {
                itemValues[j] = allSnItemValueList.get(j);
                if (!StringUtils.isBlankWithSpecialNumber(String.valueOf(itemValues[j]))) {
                    snItemNormalList.add(itemValues[j]);
                }
            }
            baseDtoResult1.setValue(getAverage(itemValues));
            toatlMeanList.add(baseDtoResult1);
            if (snItemNormalList.isEmpty()) {
                baseDtoResult2.setValue("-");
            } else {
                baseDtoResult2.setValue(getRange(Collections.max(snItemNormalList), Collections.min(snItemNormalList)));
            }
            toalRangList.add(baseDtoResult2);
        }
        grrStatisticDataDto.setTotalMeanList(toatlMeanList);
        grrStatisticDataDto.setTotalRangList(toalRangList);
        grrStatisticDataDtoList.add(grrStatisticDataDto);

        resultDto.setGrrDataDtoList(grrDataDtoResultList);
        resultDto.setGrrStatisticDataDtoList(grrStatisticDataDtoList);
        return resultDto;
    }

    private String getAverage(double[] array) {
        double sum = 0;
        double count = 0;
        if (array == null || array.length == 0) {
            return "-";
        }
        for (int i = 0; i < array.length; i++) {
            if (StringUtils.isBlankWithSpecialNumber(String.valueOf(array[i]))) {
                continue;
            }
            sum += array[i];
            count++;
        }
        if (count == 0) {
            return "-";
        }

        return String.valueOf(sum / count);
    }

    private String getRange(double max, double min) {
        return String.valueOf(max - min);
    }

    private String getDistinctGategories(String partSigma, String grrSigma){
        if (partSigma == null || grrSigma == null) {
            return "-";
        }

        if (grrSigma != null && (grrSigma.equals("-") || partSigma.equals("-") || Double.valueOf(grrSigma) == 0D)) {
            return "-";
        }

        Double disinctGategories = (Double.valueOf(partSigma)/Double.valueOf(grrSigma)) * 1.41;
        return String.valueOf((int) Math.floor(disinctGategories));
    }

}
